/***************************************************************
*  NAME:      digest
*
*  SYNOPSIS:  Implement the digest api.
*    	    
*  DESCRIPTION:
*     	    
*  HISTORY:
*      	         pascal - Jan 22, 2012:  Created.
*
***************************************************************/


/* $Id$ */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "digest.h"

void update_digest(digest_ctx *context, const unsigned char *input, int input_len)
{
	context->input_len += input_len;

	// process any left over from the last call to "update_digest"
	if (context->block_len > 0)
	{
		// How much is needed to do a full block
		int borrow_len = DIGEST_BLOCK_SIZE - context->block_len;


		if (input_len < borrow_len) {
			// there is  not enough input to fill the block.
			memcpy(context->block+context->block_len, input, input_len);
			context->block_len += input_len;
			return;
		}
		else
		{
			memcpy(context->block+context->block_len, input, borrow_len);
			context->block_operate(context->block, context->hash);
			context->block_len=0;
			input_len -= borrow_len;
			input += borrow_len;
		}
	}
	while (input_len > DIGEST_BLOCK_SIZE) {
		context->block_operate(input, context->hash);
		input += DIGEST_BLOCK_SIZE;
		input_len -= DIGEST_BLOCK_SIZE;
	}

	if (input_len > 0) {
		memcpy(context->block, input, input_len);
		context->block_len = input_len;
	}
}


void swap_digest(digest_ctx *context)
{
        int k;

        for(k=0; k<context->hash_len; k++)
                context->hash[k] = htonl(context->hash[k]);
}


#define INPUT_BLOCK_SIZE 56

void finalize_digest(digest_ctx *context)
{
	memset(context->block+context->block_len, 0, DIGEST_BLOCK_SIZE - context->block_len);

	context->block [context->block_len] = 0x80;

	// handling if the last block length is between 56 and 64

	if (context->block_len >= INPUT_BLOCK_SIZE)
	{
		context->block_operate(context->block, context->hash);
		context->block_len = 0;
		// TO BE FIXED:
		memset (context->block, 0, DIGEST_BLOCK_SIZE);
	}
	// Only append the length to the last block
	// Technically this allows for 64 bits of length, but we process only 32 bits here.
	context->block_finalize(context->block, context->input_len*8);
	context->block_operate(context->block, context->hash);

	swap_digest(context);
}


void new_digest(digest_ctx * context)
{
        if (context->new_ctx == NULL) {
                fprintf(stderr, "new_digest: unkown digest\n");
                return;
        }
        
        free(context->hash);
        context->new_ctx(context);
}

void memdumpex (char * func, char *name, unsigned char *mem, size_t n, size_t lmax);

void print_digest(char * name, digest_ctx * context)
{
	char * fn = NULL;
	switch (context->dtype) {
	case digest_none:
		fn = "digest_none"; 
		break;
	case digest_MD5:
		fn = "digest MD5"; 
		break;
	case digest_SHA1:
		fn = "digest SHA1"; 
		break;
	case digest_SHA256:
		fn = "digest SHA256"; 
		break;
	}
	memdumpex(fn,name, (char*)context->hash, context->hash_len*sizeof(unsigned int), 80);
}
